<?php
/*
 +----------------------------------------------------------------------
 + Title        : Auth 控制器
 + Author       : Randy_chen
 + Version      : V1.0.0.1
 + Initial-Time : 2021/4/2 9:50
 + Last-time    : 2021/4/2 9:50+ chen2
 + Desc         : Auth
 +----------------------------------------------------------------------
*/


namespace app\http\middleware;


use app\admin\model\AdminAuthGroup;
use app\admin\model\Api;
use app\admin\service\AdminService;
use app\common\service\TokenService;
use app\http\exception\BadRequestHttpException;
use app\user\model\User;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Cache;

use think\facade\Config;
use Throwable;

class Auth
{
    private $auth;
    public  $request;
    private $apiDebug;
    private $token;

    private string $appSecret;
    private        $sign;
    /**
     * @var mixed|string
     */
    private mixed $trans_id;
    /**
     * @var mixed|string
     */
    private mixed $timestamp;
    private mixed $params;


    /**
     * @throws Throwable
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    public function handle($request, \Closure $next)
    {
        $this->request = $request;
        // 验证请求方式
        if (!in_array($this->request->method(), ['GET', 'POST', 'OPTIONS'])) {
            abort(404, '不支持的请求方式');
        }
        $params = $request->post();
        $apikey = $params['app_key'] ?? "";
        $this->timestamp = $params['timestamp'] ?? '';
        $this->sign = $params['sign'] ?? '';
        $this->apiDebug = $params['api_debug'] ?? '';
        $this->trans_id = $params['trans_id'] ?? '';
        $app = \app\common\model\App::build()
                                    ->where('app.app_key', $apikey)
                                    ->find();
//        dd(Config::get('randy'));
        if (!$app) {
            error_abort('应用不存在!');
        }
        if ($app->status != 1) {
            error_abort('应用未启动!');
        }
        $this->appSecret = $app->app_secret;
        $this->params = $params;
        $this->checkSign();
        $this->checkTime();
        $this->checkTrans();
        unset($params['app_key']);
        unset($params['token']);
        unset($params['timestamp']);
        unset($params['format']);
        unset($params['method']);
        unset($params['sign']);
        unset($params['trans_id']);
        unset($params['api_debug']);
        $request->requestParams = $params;
        // API_DEBUG模式是否运行
        $this->token = get_token();
        $this->checkToken();
        $this->checkAuth();
        return $next($request);
    }


    /**
     * 只验证Token是否合法,否则一律按游客处理
     *
     * @access private
     * @return string|true
     * @throws throwable
     */
    private function checkToken()
    {
        $GLOBALS['client'] = [
            'type'        => config('extra.client_group.' . ($this->apiDebug ? 'user' : 'visitor') . '.value'),
            'group_id'    => $this->apiDebug ? AUTH_CLIENT : AUTH_GUEST,
            'client_id'   => $this->apiDebug ? 1 : 0,
            'client_name' => $this->apiDebug ? 'yl' : '游客',
            'token'       => $this->token,
        ];
        $token = $this->token;
        if (!$token) {
            return true;
        }
        $user = TokenService::checkToken($token);
        $stores = 'ALL';
        switch (strtoupper($user['platform'])) {
            case 'APP':
                $userinfo = User::build()
                                ->find($user['user_id']);
                $userinfo['admin_id'] = $userinfo['user_id'];
                $userinfo['username'] = $userinfo['username'] ?? $userinfo['nickname'];
                $userinfo['group_id'] = 3;
                break;
            case "PLATFORM":
            case "ADMIN":
            case "WORK":
                $service = new AdminService();
                $userinfo = $service->getAdminItem(['admin_id' => $user['user_id']]);
                break;
            default:
                $service = new AdminService();
                $userinfo = $service->getAdminItem(['admin_id' => $user['user_id']]);
        }
        //设置全局信息
        $GLOBALS['client'] = [
            'type'        => $user['platform'],
            'group_id'    => $userinfo['group_id'],
            'client_id'   => $userinfo['admin_id'],
            'client_name' => $userinfo['username'],
            'token'       => $token,
            'stores'      => $stores,
            'user'        => $userinfo
        ];
        return true;
    }

    //验证权限

    /**
     * 验证Auth
     *
     * @access private
     * @return void
     * @throws throwable
     */
    private function checkAuth() : void
    {
        return ;
        // 获取当前权限点
        $url = $this->getAuthUrl();
        $api = Api::build()
                  ->cache(true, 60)
                  ->where('api.api_url', $url)
                  ->find();
        if (!$api) {
            error_abort('未开放该接口, 请联系管理员开放权限');
        }

        // 批量API调用或调试模式不需要权限验证
        if ($this->apiDebug) {
            return;
        }

        $group = AdminAuthGroup::build()
//                               ->cache(true, 60)
                               ->where('group_id', get_group_id())
                               ->find();
        if (in_array($api->api_id, $group->api_rules)) {
            return;
        }
        error_abort('权限不足, 请联系管理员开放权限');
    }

    /**
     * 验证Sign是否合法
     *
     * @return void
     * @author : Randy_chen
     * @Date   : 2023/5/20
     * @Time   : 23:46
     */
    private function checkSign() : void
    {
        if (empty($this->params['sign'])) {
            return ;
        }

        unset($this->params['sign']);
        $params = $this->params;
        ksort($params);

        $type = ['array', 'object', 'NULL'];
        $stringToBeSigned = $this->appSecret;
        foreach ($params as $key => $val) {
            if ($key != '' && !in_array(gettype($val), $type)) {
                $stringToBeSigned .= $key . $val;
            }
        }
        unset($key, $val);
        $stringToBeSigned .= $this->appSecret;

        if (!hash_equals(md5($stringToBeSigned), $this->sign)) {
//            throw new BadRequestHttpException('签名错误!');
        }
    }


    private function checkTime() : void
    {
        if (ceil(time() - $this->timestamp) > 60) {
//            throw new BadRequestHttpException('请求已超期!');
        }
    }

    private function checkTrans() : void
    {
        $key = 'API:TARNS:' . $this->trans_id;
        if (Cache::get($key)) {
//            throw new BadRequestHttpException('请求流水号已存在, 请勿重复请求!');
        }
        Cache::set($key, 1, 3600);
    }

    private function getAuthUrl() : string
    {
        return request()->baseUrl();
    }
}
